package cn.xiaobai.utils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Arrays;

/**
 * 日志打印工具
 *
 * @Author yangdaji
 * @Date 2023/11/29
 * @PackageName cn.xiaobai.utils
 * @ClassName LoggerUtils
 */
public class LoggerFactory {


    public static Logger getLogger(Class<?> className) {
        return new Logger(className);
    }


    public static class Logger {

        static LocalDateTime tiem = LocalDateTime.now();
        static DateTimeFormatter formatter = null;
        static final String pattern = "yyyy-MM-dd HH:mm:ss.SSS";

        static {
            DateTimeFormatterBuilder dateTimeFormatterBuilder = new DateTimeFormatterBuilder();
            formatter = dateTimeFormatterBuilder.appendPattern(pattern).toFormatter();
        }

        private Class<?> className;

        public Logger(Class<?> className) {
            this.className = className;
        }

        public void info(String template, Object... messages) {
            print(Level.INFO.num, template, messages);
        }

        public void warn(String template, Object... messages) {
            print(Level.WRA.num, template, messages);
        }

        public void error(String template, Object... messages) {
            print(Level.ERROR.num, template, messages);
        }


        void print(int level, String template, Object... messages) {
            boolean printTemplate = false;
            // setup1: template == ""
            if (!isNonBlank(template)) {
                return;
            }
            // setup2: message ==""
            // 打印模板
            if (isEmptyArray(messages)) {
                printTemplate = true;
            }

            // 转换模板格式
            if (template.contains("{}")) {
                int count = getCount(template);
                int length = messages.length;
                if (length < count) {
                    // 计算循环次数,删除多余的替换符, 直到替换符的数量小于等于 消息数量
                    int num = count - length;
                    for (int i = 0; i < num; i++) {
                        template = template.replaceFirst("\\{}", "");
                    }
                }

                // 格式化消息为空, 则不转换
                String replacement = "";
                if (!printTemplate) {
                    replacement = "%s";
                }
                template = template.replace("{}", replacement);
            }
            Thread thread = Thread.currentThread();
            String levelStr = getTime() + "  level  " + thread.getId() + " ---- [  \t\t\t\t" + thread.getName() + " ]" + className.getName() + "    :  \t";
            if (level == 1) {
                levelStr = levelStr.replace("level", "info");
            } else if (level == 2) {
                levelStr = levelStr.replace("level", "war");
            } else {
                levelStr = levelStr.replace("level", "error");
            }

            System.out.println(levelStr + String.format(template, messages));
        }


        static String getTime() {
            return tiem.format(formatter);
        }

        static int getCount(String str) {
            if (isBlank(str)) {
                return 0;
            }
            int length = str.length();
            char prefix = '{';
            char suffix = '}';
            int count = 0;
            for (int j = 0; j < length; j++) {
                char c2 = str.charAt(j);
                if (prefix == c2 && j + 1 < length) {
                    char c3 = str.charAt(j + 1);
                    if (suffix == c3) {
                        count++;
                    }
                }

            }
            return count;
        }

        static boolean isBlank(String str) {
            return str == null || str.isEmpty();
        }

        static boolean isNonBlank(String str) {
            return !isBlank(str);
        }

        static boolean isEmptyArray(Object[] strs) {
            return strs == null && strs.length == 0;
        }

        enum Level {
            INFO(1), WRA(2), ERROR(3);

            private int num;

            Level(int num) {
                this.num = num;
            }

            public int getNum() {
                return num;
            }
        }

    }


}
